home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C++ / Applications / Nuntius 1.2 / src / Nuntius / UNetAsciiConverter.cp < prev    next >
Encoding:
Text File  |  1994-02-20  |  10.1 KB  |  426 lines  |  [TEXT/MPS ]

  1. // Copyright © 1993 Peter Speck (speck@dat.ruc.dk).  All rights reserved.
  2. // UNetAsciiConverter.cp
  3.  
  4. #include "UNetAsciiConverter.h"
  5.  
  6. #include <ToolUtils.h>
  7.  
  8. #pragma segment MyArticle
  9.  
  10.  
  11. /*
  12.  * According to the ISO 2022, I think it is permitted
  13.  * to use space character code when Japanese double code
  14.  * (or other 96^n type multiple byte code) is indicated to G0.
  15.  *
  16.  * However, almost all Japanese terminal do not permit to
  17.  * use it.
  18.  */
  19. #define        UGLYDUCK
  20.  
  21. /*
  22.  * Many interfaces like nntp needs that a text ends with
  23.  * newline code. If a internal text ends with a double byte char
  24.  * and a newline, the result of this conversion will be
  25.  * double byte char, newline and indication string.
  26.  * This may not work with nntp. Define RESET_ON_NL to
  27.  * add a roman indication string on the end of each line.
  28.  */
  29. #define    RESET_ON_NL
  30.  
  31. /*
  32.  *
  33.  * Code table sectioning
  34.  *
  35.  */
  36. #define        _R        1        /* Roman */
  37. #define        _K        2        /* Japanese Katakana */
  38. #define        _S        4        /* Shift JIS --- Macintosh Japanese Code */
  39. #define        _2        8        /* Shift JIS 2nd byte */
  40. #define        _T        0        /* Other should be unknown or through */
  41.  
  42. #ifdef        UGLYDUCK
  43. #define        _SP        _R
  44. #else        /* UGLYDUCK */
  45. #define        _SP        _T
  46. #endif        /* UGLYDUCK */
  47.  
  48. #ifdef    RESET_ON_NL
  49. #define    _NL    _R
  50. #else    /* RESET_ON_NL */
  51. #define    _NL    _T
  52. #endif    /* RESET_ON_NL */
  53.  
  54. static unsigned char secTable[256] = {
  55. /*0*/    _T,        _T,        _T,        _T,        _T,        _T,        _T,        _T,
  56.         _T,        _T,        _NL,    _T,        _T,        _NL,    _T,        _T,
  57. /*1*/    _T,        _T,        _T,        _T,        _T,        _T,        _T,        _T,
  58.         _T,        _T,        _T,        _T,        _T,        _T,        _T,        _T,
  59. /*2*/    _SP,    _R,        _R,        _R,        _R,        _R,        _R,        _R,
  60.         _R,        _R,        _R,        _R,        _R,        _R,        _R,        _R,
  61. /*3*/    _R,        _R,        _R,        _R,        _R,        _R,        _R,        _R,
  62.         _R,        _R,        _R,        _R,        _R,        _R,        _R,        _R,
  63. /*4*/    _R|_2,    _R|_2,    _R|_2,    _R|_2,    _R|_2,    _R|_2,    _R|_2,    _R|_2,
  64.         _R|_2,    _R|_2,    _R|_2,    _R|_2,    _R|_2,    _R|_2,    _R|_2,    _R|_2,
  65. /*5*/    _R|_2,    _R|_2,    _R|_2,    _R|_2,    _R|_2,    _R|_2,    _R|_2,    _R|_2,
  66.         _R|_2,    _R|_2,    _R|_2,    _R|_2,    _R|_2,    _R|_2,    _R|_2,    _R|_2,
  67. /*6*/    _R|_2,    _R|_2,    _R|_2,    _R|_2,    _R|_2,    _R|_2,    _R|_2,    _R|_2,
  68.         _R|_2,    _R|_2,    _R|_2,    _R|_2,    _R|_2,    _R|_2,    _R|_2,    _R|_2,
  69. /*7*/    _R|_2,    _R|_2,    _R|_2,    _R|_2,    _R|_2,    _R|_2,    _R|_2,    _R|_2,
  70.         _R|_2,    _R|_2,    _R|_2,    _R|_2,    _R|_2,    _R|_2,    _R|_2,    _T,
  71. /*8*/    _T|_2,    _S|_2,    _S|_2,    _S|_2,    _S|_2,    _S|_2,    _S|_2,    _S|_2,
  72.         _S|_2,    _S|_2,    _S|_2,    _S|_2,    _S|_2,    _S|_2,    _S|_2,    _S|_2,
  73. /*9*/    _S|_2,    _S|_2,    _S|_2,    _S|_2,    _S|_2,    _S|_2,    _S|_2,    _S|_2,
  74.         _S|_2,    _S|_2,    _S|_2,    _S|_2,    _S|_2,    _S|_2,    _S|_2,    _S|_2,
  75. /*A*/    _K|_2,    _K|_2,    _K|_2,    _K|_2,    _K|_2,    _K|_2,    _K|_2,    _K|_2,
  76.         _K|_2,    _K|_2,    _K|_2,    _K|_2,    _K|_2,    _K|_2,    _K|_2,    _K|_2,
  77. /*B*/    _K|_2,    _K|_2,    _K|_2,    _K|_2,    _K|_2,    _K|_2,    _K|_2,    _K|_2,
  78.         _K|_2,    _K|_2,    _K|_2,    _K|_2,    _K|_2,    _K|_2,    _K|_2,    _K|_2,
  79. /*C*/    _K|_2,    _K|_2,    _K|_2,    _K|_2,    _K|_2,    _K|_2,    _K|_2,    _K|_2,
  80.         _K|_2,    _K|_2,    _K|_2,    _K|_2,    _K|_2,    _K|_2,    _K|_2,    _K|_2,
  81. /*D*/    _K|_2,    _K|_2,    _K|_2,    _K|_2,    _K|_2,    _K|_2,    _K|_2,    _K|_2,
  82.         _K|_2,    _K|_2,    _K|_2,    _K|_2,    _K|_2,    _K|_2,    _K|_2,    _K|_2,
  83. /*E*/    _S|_2,    _S|_2,    _S|_2,    _S|_2,    _S|_2,    _S|_2,    _S|_2,    _S|_2,
  84.         _S|_2,    _S|_2,    _S|_2,    _S|_2,    _S|_2,    _S|_2,    _S|_2,    _S|_2,
  85. /*F*/    _T|_2,    _T|_2,    _T|_2,    _T|_2,    _T|_2,    _T|_2,    _T|_2,    _T|_2,
  86.         _T|_2,    _T|_2,    _T|_2,    _T|_2,    _T|_2,    _T,        _T,        _T,
  87. };
  88.  
  89. #define        isTH(c)            (secTable[c] == _T)
  90. #define        isRO(c)            (secTable[c] & _R)
  91. #define        isKT(c)            (secTable[c] & _K)
  92. #define        isSJ(c)            (secTable[c] & _S)
  93. #define        isSJ2(c)        (secTable[c] & _2)
  94.  
  95.  
  96.  
  97. #if 0
  98. /* This array should be ordered as TCV_???? index above */
  99. indicator indTable[] =
  100. {
  101.     { 0x28, 0x42, kAscii0, 0, im_roman, ex_roman },        /* TCV_USRO */
  102.     { 0x28, 0x49, kAscii0, 0, im_kana,  ex_kana  },        /* TCV_JPKT */
  103.     { 0x28, 0x4a, kAscii0, 0, im_roman, ex_roman },        /* TCV_JPRO */
  104.     { 0x24, 0x40, kAscii0, 0, im_kanji, ex_kanji },        /* TCV_JPK1 */
  105.     { 0x24, 0x42, kAscii0, 0, im_kanji, ex_kanji }        /* TCV_JPK2 */
  106. };
  107. #endif
  108.  
  109. PTextCodeConverter::PTextCodeConverter()
  110.     : PPtrObject()
  111. {
  112.     fImportFunc = &PTextCodeConverter::im_roman;
  113.     fExportFunc = &PTextCodeConverter::ex_roman;
  114. }
  115.  
  116. PTextCodeConverter::~PTextCodeConverter()
  117. {
  118. }
  119.  
  120. /* Which code set is now indicated by the network code. */
  121. Boolean PTextCodeConverter::ImportSwitch()
  122. {
  123.     unsigned char ch1 = GetNextChar();
  124.     unsigned char ch2;
  125.     if (ch1 == 0x28)
  126.     {
  127.         ch2 = GetNextChar();
  128.         switch (ch2)
  129.         {
  130.             case 0x00: return false; // end of text
  131.             case 0x42: fImportFunc = &PTextCodeConverter::im_roman; break;
  132.             case 0x49: fImportFunc = &PTextCodeConverter::im_kana;  break;
  133.             case 0x4a: fImportFunc = &PTextCodeConverter::im_roman; break;
  134.             default:
  135.              if (qDebug)
  136.                  fprintf(stderr, "Unknown encoding escape = esc,%ld,%ld, switching to roman\n", long(ch1), long(ch2));
  137.             fImportFunc = &PTextCodeConverter::im_roman;
  138.         }
  139.     }
  140.     else if (ch1 == 0x24)
  141.     {
  142.         ch2 = GetNextChar();
  143.         switch (ch2)
  144.         {
  145.             case 0x00: return false; // end of text
  146.             case 0x40: fImportFunc = &PTextCodeConverter::im_kanji;  break;
  147.             case 0x42: fImportFunc = &PTextCodeConverter::im_kanji;  break;
  148.             default:
  149.              if (qDebug)
  150.                  fprintf(stderr, "Unknown encoding escape = esc,%ld,%ld, switching to roman\n", long(ch1), long(ch2));
  151.             fImportFunc = &PTextCodeConverter::im_roman;
  152.         }
  153.     }
  154.     return true;
  155. }
  156.  
  157. /* importing roman */
  158. Boolean PTextCodeConverter::im_roman()
  159. {
  160.     while (true)
  161.     {
  162.         unsigned char ch = GetNextChar();
  163.         if (!ch)
  164.             return false;
  165.         if (ch == chEscape)
  166.             return true;
  167.         OutputOneChar(ch);
  168.     }
  169. }
  170.  
  171. /* importing japanese katakana */
  172. Boolean PTextCodeConverter::im_kana()
  173. {
  174.     while (true)
  175.     {
  176.         unsigned char ch = GetNextChar();
  177.         if (!ch)
  178.             return false;
  179.         if (ch == chEscape)
  180.             return true;
  181.         if (isKT(ch))
  182.             ch += 0x80;
  183.         OutputOneChar(ch);
  184.     }
  185. }
  186.  
  187. /* importing japanese kanji */
  188. Boolean PTextCodeConverter::im_kanji()
  189. {
  190.     unsigned char ch1 = GetNextChar();
  191.     while (true)
  192.     {
  193.         if (!ch1)
  194.             return false;
  195.         if (ch1 == chEscape)
  196.             return true;
  197.         unsigned char ch2 = GetNextChar();
  198.         if (isRO(ch1) && isRO(ch2)) 
  199.         {
  200.             ch1 |= 0x80;
  201.             ch2 |= 0x80;
  202.             if (ch1 & 0x01) 
  203.             {
  204.                 ch1 = ch1 / 2 + (ch1 < 0xdf ? 0x31 : 0x71);
  205.                 ch2 = ch2 - (ch2 >= 0xe0 ? 0x60 : 0x61);
  206.             }
  207.             else
  208.             {
  209.                 ch1 = ch1 / 2 + (ch1 < 0xdf ? 0x30 : 0x70);
  210.                 ch2 = ch2 - 2;
  211.             }
  212.             OutputTwoChars(ch1, ch2);
  213.             ch1 = GetNextChar();
  214.         } 
  215.         else
  216.         {
  217.             OutputOneChar(ch1);
  218.             ch1 = ch2;
  219.         }
  220.     }
  221. }
  222.  
  223. void PTextCodeConverter::ExportSwitchToRoman()
  224. {
  225.     OutputOneChar(chEscape);
  226.     OutputTwoChars(0x28, 0x4a);
  227.     fExportFunc = &PTextCodeConverter::ex_roman;
  228. }
  229.  
  230. void PTextCodeConverter::ExportSwitchToKatakana()
  231. {
  232.     OutputOneChar(chEscape);
  233.     OutputTwoChars(0x28, 0x49);
  234.     fExportFunc = &PTextCodeConverter::ex_kana;
  235. }
  236.  
  237. void PTextCodeConverter::ExportSwitchToKanji()
  238. {
  239.     OutputOneChar(chEscape);
  240.     OutputTwoChars(0x24, 0x42);        /* kanji should use the newer code */
  241.     fExportFunc = &PTextCodeConverter::ex_kanji;
  242. }
  243.  
  244. /* exporting roman */
  245. Boolean PTextCodeConverter::ex_roman()
  246. {
  247.     unsigned char ch = fCurrentExportChar;
  248.     while (true)
  249.     {
  250.         if (!ch)
  251.             return false;
  252.         if (isKT(ch))
  253.         {
  254.             ExportSwitchToKatakana();        /* katakana */
  255.             return true;
  256.         }
  257.         if (isSJ(ch))
  258.         {
  259.             ExportSwitchToKanji();
  260.             return true;
  261.         }
  262.         /* RO and UN need no conversion */
  263.         OutputOneChar(ch);
  264.         fCurrentExportChar = ch = GetNextChar();
  265.     }
  266. }
  267.  
  268. Boolean PTextCodeConverter::ex_kana()
  269. {
  270.     unsigned char ch = fCurrentExportChar;
  271.     while (true)
  272.     {
  273.         if (!ch)
  274.             return false;
  275.         // disse isXXX kan laves meget mere effektivt ved at lave switch
  276.         // direkte på den værdi der fås fra tabellen, og så med mange case's
  277.         if (isRO(ch))
  278.         {
  279.             ExportSwitchToRoman();        /* roman */
  280.             return true;
  281.         }
  282.         if (isSJ(ch))
  283.         {
  284.             ExportSwitchToKanji();
  285.             return true;
  286.         }
  287.         if (isKT(ch))
  288.             ch -= 0x80;
  289.         /* UN needs no conversion */
  290.         OutputOneChar(ch);
  291.         fCurrentExportChar = ch = GetNextChar();
  292.     }
  293. }
  294.  
  295. Boolean PTextCodeConverter::ex_kanji()
  296. {
  297.     unsigned char ch1 = fCurrentExportChar;
  298.     while (true)
  299.     {
  300.         if (!ch1)
  301.             return false;
  302.         if (isRO(ch1))
  303.         {
  304.             ExportSwitchToRoman();        /* roman */
  305.             return true;
  306.         }
  307.         if (isKT(ch1)) 
  308.         {
  309.             ExportSwitchToKatakana();
  310.             return true;
  311.         }
  312.         unsigned char ch2 = GetNextChar();
  313.         fCurrentExportChar = ch2;
  314.         if (isSJ(ch1) && isSJ2(ch2)) 
  315.         {
  316.             if (ch2 >= 0x9f) 
  317.             {
  318.                 ch1 = (ch1*2 - (ch1 >= 0xe0 ? 0xe0 : 0x60)) & 0x7f;
  319.                 ch2 = ch2 - 0x7e;
  320.             }
  321.             else
  322.             {
  323.                 ch1 = (ch1*2 - (ch1 >= 0xe0 ? 0xe1 : 0x61)) & 0x7f;
  324.                 ch2 = (ch2 + (ch2 >= 0x7f ? 0x60 : 0x61)) & 0x7f;
  325.             }
  326.             OutputTwoChars(ch1, ch2);
  327.             fCurrentExportChar = ch1 = GetNextChar();
  328.         }
  329.         else
  330.         {
  331.             OutputOneChar(ch1);
  332.             ch1 = ch2; // ate one too much
  333.         }
  334.     }
  335. }
  336.  
  337. void PTextCodeConverter::ConvertNet2Mac()
  338. {
  339.     fImportFunc = &PTextCodeConverter::im_roman;
  340.     while ((this->*PTextCodeConverter::fImportFunc)())
  341.         if (!ImportSwitch())
  342.             return;
  343. }
  344.  
  345. void PTextCodeConverter::ConvertMac2Net()
  346. {
  347.     fExportFunc = &PTextCodeConverter::ex_roman;
  348.     fCurrentExportChar = GetNextChar();
  349.     while ((this->*PTextCodeConverter::fExportFunc)())
  350.         ;
  351.     if (fExportFunc != &PTextCodeConverter::ex_roman)
  352.         ExportSwitchToRoman();
  353. }
  354.  
  355. //==================================================================
  356. PStringTextCodeConverter::PStringTextCodeConverter(const CStr255 &inputString)
  357.     : PTextCodeConverter(), fInputString(inputString)
  358. {
  359. }
  360.  
  361. PStringTextCodeConverter::~PStringTextCodeConverter()
  362. {
  363. }
  364.         
  365. void PStringTextCodeConverter::ConvertNet2Mac()
  366. {
  367.     fOutputString = "";
  368.     fInputIndex = 1;
  369.     PTextCodeConverter::ConvertNet2Mac();
  370. }
  371.  
  372. void PStringTextCodeConverter::ConvertMac2Net()
  373. {    
  374.     fOutputString = "";
  375.     fInputIndex = 1;
  376.     PTextCodeConverter::ConvertMac2Net();
  377. }
  378.  
  379. unsigned char PStringTextCodeConverter::GetNextChar()
  380. {
  381.     if (fInputIndex <= fInputString.Length())
  382.         return fInputString[fInputIndex++];
  383.     else
  384.         return 0;
  385. }
  386.  
  387. void PStringTextCodeConverter::OutputOneChar(unsigned char ch)
  388. {
  389.     fOutputString += ch;
  390. }
  391.  
  392. void PStringTextCodeConverter::OutputTwoChars(unsigned char ch1, unsigned char ch2)
  393. {
  394.     fOutputString += ch1;
  395.     fOutputString += ch2;
  396. }
  397.  
  398. void DumpString(const CStr255 &s)
  399. {
  400.     for (short i = 1; i <= s.Length(); ++i)
  401.     {
  402.         if ((i % 16) == 1)
  403.             fprintf(stderr, "%06lX:  ", long(i - 1));
  404.         fprintf(stderr, " %02lX", long(s[i]));
  405.         if ((i % 16) == 0)
  406.             fprintf(stderr, "\n");
  407.     }
  408.     fprintf(stderr, "\n");
  409. }
  410.  
  411. // giver mine «macroer» mon Japanerne problemer??????
  412.  
  413. void Test4() 
  414. {
  415.     CStr255 s;
  416.     PStringTextCodeConverter cnv(s);
  417.     fprintf(stderr, "net -> mac\n");
  418.     GetIndString(s, 9999, 1);
  419.     cnv.ConvertNet2Mac();
  420.     DumpString(cnv.fOutputString);
  421.     fprintf(stderr, "Mac -> net\n");
  422.     GetIndString(s, 9999, 2);
  423.     cnv.ConvertMac2Net();
  424.     DumpString(cnv.fOutputString);
  425. }
  426.